package org.yangjie;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import org.apache.poi.util.Units;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.poi.xwpf.usermodel.XWPFRun;

/**
 * Word文件处理工具
 * @author YangJie [2019年7月23日]
 */
public class WordUtil {
	
	/**
	 * 读取文本和图片
	 * @param inputStream
	 * @return
	 * @throws Exception
	 */
    public static List<List<Readable>> read(InputStream inputStream) throws Exception {
    	List<List<Readable>> resultList = new ArrayList<>();
        XWPFDocument document = new XWPFDocument(inputStream);
        List<XWPFParagraph> paragraphList = document.getParagraphs();
        for(XWPFParagraph paragraph : paragraphList) {
        	List<XWPFRun> runList = paragraph.getRuns();
        	List<Readable> rowList = new ArrayList<>();
        	for(XWPFRun run : runList) {
        		String text = run.text();
        		if (Objects.nonNull(text) && !text.trim().isEmpty()) {
        			rowList.add(ReadText.build().setText(text));
				}
        		List<XWPFPicture> pictureList = run.getEmbeddedPictures();
        		if (Objects.nonNull(pictureList) && !pictureList.isEmpty()) {
					for(XWPFPicture picture : pictureList) {
						XWPFPictureData pictureData = picture.getPictureData();
						if (Objects.nonNull(pictureData)) {
							rowList.add(ReadPicture.build().setData(pictureData.getData()).setType(pictureData.getPictureType()));
						}
					}
				}
        	}
        	resultList.add(rowList);
        }
        document.close();
        return resultList;
    }
	
	/**
	 * 读取所有文本
	 * 只能获取文本，不能获取到文本对应的属性和图片
	 * @param inputStream
	 * @return
	 * @throws Exception
	 */
	public static String readText(InputStream inputStream) throws Exception {
		String result;
		XWPFDocument document = new XWPFDocument(inputStream);
		XWPFWordExtractor extractor = new XWPFWordExtractor(document);
		result = extractor.getText();
		extractor.close();
		document.close();
		return result;
	}
	
	
	/**
	 * 创建文件
	 * @param outputStream
	 * @param List
	 * @return
	 * @throws Exception
	 */
	public static void create(OutputStream outputStream, Object... objs) throws Exception {
		create(outputStream, Arrays.asList(objs));
	}
	
	/**
	 * 创建文件
	 * @param outputStream
	 * @param List
	 * @return
	 * @throws Exception
	 */
	public static void create(OutputStream outputStream, List<Object> list) throws Exception {
		XWPFDocument document = new XWPFDocument();
		for(Object object : list) {
			writeParagraph(document, object);
		}
		document.write(outputStream);
		document.close();
	}
	
	/**
	 * 写入段落
	 * @param document
	 * @param object
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void writeParagraph(XWPFDocument document, Object obj) {
		XWPFParagraph paragraph = document.createParagraph();
		if (obj instanceof Collection) {
			((Collection)obj).forEach(item -> writeRun(paragraph, item));
		}else {
			writeRun(paragraph, obj);
		}
	}
	
	/**
	 * 写入对象
	 * @param paragraph
	 * @param obj
	 */
	private static void writeRun(XWPFParagraph paragraph, Object obj) {
		XWPFRun run = paragraph.createRun();
		if (obj instanceof WriteText) { // 文本（带格式）
			WriteText text = (WriteText)obj;
			run.setText(Objects.nonNull(text.getData()) ? String.valueOf(text.getData()) : "");
			if (text.isBold()) {
				run.setBold(text.isBold());
			}
			if (text.getSize() > 0) {
				run.setFontSize(text.getSize());
			}
			if (Objects.nonNull(text.getColor()) && !text.getColor().trim().isEmpty()) {
				run.setColor(text.getColor());
			}
		}else if (obj instanceof WritePicture) { // 图片
			WritePicture picture = (WritePicture)obj;
			if (picture.getType() > 0) {
				try(ByteArrayInputStream inputStream = new ByteArrayInputStream(picture.getData())){
					run.addPicture(inputStream, picture.getType(), "", Units.toEMU(picture.getWidth()), Units.toEMU(picture.getHeight()));
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
		}else { // 默认格式文本
			run.setText(Objects.nonNull(obj) ? String.valueOf(obj) : "");
		}
	}
	
	
	/**
	 * 定义数据读取接口
	 */
	public static interface Readable {}
	
	/**
	 * 定义数据写入接口
	 */
	public static interface Writeable{}
	
	/**
	 * 读取文本实体
	 */
	public static class ReadText implements Readable {
		String text;
		public static ReadText build() {
			return new ReadText();
		}
		public String getText() {
			return text;
		}
		public ReadText setText(String text) {
			this.text = text;
			return this;
		}
	}
	
	/**
	 * 读取图片实体
	 */
	public static class ReadPicture implements Readable {
		String type; // 图片类型（jpg|png|gif..）
		byte[] data; // 数据流
		public static ReadPicture build() {
			return new ReadPicture();
		}
		public ReadPicture setType(int type) {
			if (type == Document.PICTURE_TYPE_JPEG) {
				setType("jpg");
			}else if (type == Document.PICTURE_TYPE_PNG) {
				setType("png");
			}else if (type == Document.PICTURE_TYPE_GIF) {
				setType("gif");
			}else {
				setType(null);
			}
			return this;
		}
		public String getType() {
			return type;
		}
		public ReadPicture setType(String type) {
			this.type = type;
			return this;
		}
		public byte[] getData() {
			return data;
		}
		public ReadPicture setData(byte[] data) {
			this.data = data;
			return this;
		}
	}
	
	/**
	 * 写入数据实体
	 */
	public static class WriteText implements Writeable{
		String data;
		String color; // 字体颜色 000000
		boolean bold; // 是否加错
		int size; // 字体大小
		public static WriteText build(String data) {
			return new WriteText().setData(data);
		}
		public String getData() {
			return data;
		}
		public WriteText setData(String data) {
			this.data = data;
			return this;
		}
		public String getColor() {
			return color;
		}
		public WriteText setColor(String color) {
			this.color = color;
			return this;
		}
		public boolean isBold() {
			return bold;
		}
		public WriteText setBold(boolean bold) {
			this.bold = bold;
			return this;
		}
		public int getSize() {
			return size;
		}
		public WriteText setSize(int size) {
			this.size = size;
			return this;
		}
	}
	
	/**
	 * 写入数据实体
	 */
	public static class WritePicture implements Writeable{
		public static enum Type{JPG,PNG,GIF};
		byte[] data; // 图片数据
		int type; // 图片类型
		int width; // 宽度px
		int height; // 高度px
		public static WritePicture build(byte[] data, Type type, int width, int height) {
			return new WritePicture().setData(data).setType(type).setWidth(width).setHeight(height);
		}
		public WritePicture setType(Type type) {
			if (type == Type.JPG) {
				setType(Document.PICTURE_TYPE_JPEG);
			}else if (type == Type.PNG) {
				setType(Document.PICTURE_TYPE_PNG);
			}else if (type == Type.GIF) {
				setType(Document.PICTURE_TYPE_GIF);
			}else {
				setType(-1);
			}
			return this;
		}
		public byte[] getData() {
			return data;
		}
		public WritePicture setData(byte[] data) {
			this.data = data;
			return this;
		}
		public int getType() {
			return type;
		}
		public WritePicture setType(int type) {
			this.type = type;
			return this;
		}
		public int getWidth() {
			return width;
		}
		public WritePicture setWidth(int width) {
			this.width = width;
			return this;
		}
		public int getHeight() {
			return height;
		}
		public WritePicture setHeight(int height) {
			this.height = height;
			return this;
		}
	}	

}
